using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Admin.NET.Application.AttributeInfo;
using Admin.NET.Application.Entity;
using Admin.NET.Application.Entity.Business;
using Admin.NET.Application.Enums;
using Admin.NET.Application.EventBus;
using Admin.NET.Application.Excel;
using Admin.NET.Application.Mqtt;
using Admin.NET.Application.Mqtt.mqttresponse;
using Admin.NET.Application.oPTIONS;
using Admin.NET.Application.Service.Collector.Dto;
using Admin.NET.Application.Service.Electricity.Dto;
using Admin.NET.Application.Util;
using Admin.NET.Core;
using EventMsg;
using Furion;
using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.EventBus;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MQTTnet;
using MQTTnet.Protocol;
using Newtonsoft.Json;
using SqlSugar;

namespace Admin.NET.Application.Service.Electricity;

[ApiDescriptionSettings(new string[] { "业务应用" }, Order = 100)]
public class ElectricityService : IDynamicApiController, ITransient, IPrivateDependency
{
	private readonly SqlSugarRepository<ElectricMeter> _rep;

	private readonly SqlSugarRepository<DeleteMeter> _repDel;

	private readonly SqlSugarRepository<Room> _repRoom;

	private readonly SqlSugarRepository<Building> _repBuilding;

	private readonly IEventPublisher _eventPublisher;

	private readonly SqlSugarRepository<RoomBalanceRecord> _balanceRep;

	private readonly RoomService _roomService;

	public ElectricityService(SqlSugarRepository<Room> repRoom, SqlSugarRepository<Building> repBuilding, SqlSugarRepository<DeleteMeter> repDel, SqlSugarRepository<ElectricMeter> rep, IEventPublisher eventPublisher, SqlSugarRepository<RoomBalanceRecord> balanceRep, RoomService roomService)
	{
		_repRoom = repRoom;
		_repBuilding = repBuilding;
		_repDel = repDel;
		_rep = rep;
		_eventPublisher = eventPublisher;
		_balanceRep = balanceRep;
		_roomService = roomService;
	}

	/// <summary>
	/// 下发
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/setting")]
	[OperationLog("下发表数据", "name")]
	public async Task SettingMeter(BaseIdInput input)
	{
		ElectricMeter collector = await (from u in _rep.AsQueryable()
			where u.Id == input.Id
			select u).FirstAsync();
		IotMqttClient mqttInfo = App.GetService<IotMqttClient>();
		if (collector != null)
		{
			ISyncEventConsistency eventmsg = App.GetService<ISyncEventConsistency>();
			if ((await eventmsg.AddEventAsync(collector.Sn + "event")).Code != EventEnum.Wait)
			{
				throw Oops.Oh(ErrorCodeEnumEx.X1001);
			}
			EventParameterResponse<string> result = await eventmsg.ExcuteEvent<string>(collector.Sn + "event", async delegate
			{
				ModelMqttResponse modelMqtt = new ModelMqttResponse
				{
					o = 3,
					d = JsonConvert.SerializeObject(new string[1] { collector.Addr })
				};
				string infomsg = JsonConvert.SerializeObject(modelMqtt);
				SMEncryptionOptions sm4options = App.GetOptions<SMEncryptionOptions>();
				if (!string.IsNullOrWhiteSpace(sm4options.Secretkey))
				{
					infomsg = AesCryptoUtil.Encrypt(infomsg, sm4options.Secretkey);
				}
				MqttApplicationMessage message = new MqttApplicationMessage
				{
					Topic = "/iotmonitor/" + collector.Sn,
					Payload = Encoding.UTF8.GetBytes(infomsg),
					QualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce
				};
				await mqttInfo.mqttClient.PublishAsync(message);
			}, null);
			collector.IssuedStatus = 3;
			if (result.Code != EventEnum.Sucess)
			{
				_rep.Context.Updateable(collector).UpdateColumns((ElectricMeter u) => new { u.IssuedStatus }).ExecuteCommand();
				throw Oops.Oh(ErrorCodeEnumEx.X1002);
			}
			if (string.IsNullOrEmpty(result.Body))
			{
				return;
			}
			string[] id = JsonConvert.DeserializeObject<string[]>(result.Body);
			if (id != null && id.Length != 0 && id[0] == collector.Addr)
			{
				_rep.Context.Updateable(collector).UpdateColumns((ElectricMeter u) => new { u.IssuedStatus }).ExecuteCommand();
			}
			return;
		}
		throw Oops.Oh(ErrorCodeEnum.xg1002);
	}

	/// <summary>
	/// 抄表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/reading")]
	[OperationLog("电表抄表", "name")]
	public async Task ReadingMeter(BaseIdInput input)
	{
		bool isdtu = false;
		ElectricMeter device = await (from u in _rep.AsQueryable()
			where u.Id == input.Id
			select u).FirstAsync();
		int newtype = 0;
		if (device != null)
		{
			string imei;
			if (device.ProtocolType == 0)
			{
				imei = device.Sn;
			}
			else
			{
				newtype = 1;
				Admin.NET.Application.Collector collector = await (from u in _rep.Context.Queryable<Admin.NET.Application.Collector>()
					where (long?)u.Id == device.CollectorId
					select u).FirstAsync();
				if (collector == null)
				{
					throw Oops.Bah("未有效关联采集设备");
				}
				if (collector.Status == 0)
				{
					throw Oops.Oh(ErrorCodeEnumEx.X1003);
				}
				imei = collector.Imei;
			}
			(IAggrementPlugin, BrandModel) plugin = AggrementPluginUtil.GetPlugin(device, isdtu);
			IAggrementPlugin pluginService = plugin.Item1;
			BrandModel currentModel = plugin.Item2;
			string body = ((!device.PriceRuleId.HasValue || !(device.PriceRuleId > 0)) ? pluginService.ReadCombinedTotalE(imei, device.LowAddr, currentModel.Code) : ((!(await (from u in _rep.Context.Queryable<ElectricityPriceRule>()
				where (long?)u.Id == device.PriceRuleId && u.Type == 1
				select u).AnyAsync())) ? pluginService.ReadCombinedTotalE(imei, device.LowAddr, currentModel.Code) : pluginService.ReadCombinedAllTotal(imei, device.LowAddr, currentModel.Code)));
			if (!string.IsNullOrEmpty(body))
			{
				Dictionary<string, UploadMqttInfo> dic = new Dictionary<string, UploadMqttInfo> { 
				{
					device.LowAddr,
					new UploadMqttInfo
					{
						State = ((device.GateStatus == 1) ? "0000" : "1111"),
						Alltotal = body,
						TotalE = body
					}
				} };
				EPowerService ePowerService = new EPowerService();
				await ePowerService.MeterUpload(imei, newtype, dic);
				return;
			}
			throw Oops.Bah("抄表失败，请检查表地址和通讯线");
		}
		throw Oops.Oh(ErrorCodeEnum.xg1002);
	}

	/// <summary>
	/// 电表拉合闸
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/switch")]
	public async Task SwitchMeter(InputSwitch input, long? TenantId)
	{
		ElectricMeter device = await (from u in _rep.AsQueryable()
			where u.Id == input.Id
			select u).FirstAsync();
		bool isdtu = false;
		if (device != null)
		{
			if (input.GateStatus == 1 && device.IsElectricityProtection)
			{
				DateTime now = DateTime.Now;
				if (!device.ElectricityProtectionBegin.HasValue && !device.ElectricityProtectionEnd.HasValue)
				{
					throw Oops.Bah("保电期间无法拉闸");
				}
				int num;
				if (!device.ElectricityProtectionBegin.HasValue)
				{
					DateTime value2 = now;
					DateTime? electricityProtectionEnd = device.ElectricityProtectionEnd;
					num = ((value2 < electricityProtectionEnd) ? 1 : 0);
				}
				else
				{
					num = 0;
				}
				if (num != 0)
				{
					throw Oops.Bah("保电期间无法拉闸");
				}
				int num2;
				if (!device.ElectricityProtectionEnd.HasValue)
				{
					DateTime value2 = now;
					DateTime? electricityProtectionEnd = device.ElectricityProtectionBegin;
					num2 = ((value2 > electricityProtectionEnd) ? 1 : 0);
				}
				else
				{
					num2 = 0;
				}
				if (num2 != 0)
				{
					throw Oops.Bah("保电期间无法拉闸");
				}
				int num3;
				if (device.ElectricityProtectionBegin.HasValue && device.ElectricityProtectionEnd.HasValue && device.ElectricityProtectionEnd >= now)
				{
					DateTime value2 = now;
					DateTime? electricityProtectionEnd = device.ElectricityProtectionBegin;
					num3 = ((value2 > electricityProtectionEnd) ? 1 : 0);
				}
				else
				{
					num3 = 0;
				}
				if (num3 != 0)
				{
					throw Oops.Bah("保电期间无法拉闸");
				}
			}
			string imei;
			if (device.ProtocolType == 0)
			{
				imei = device.Sn;
			}
			else
			{
				isdtu = true;
				Admin.NET.Application.Collector collector = await (from u in _rep.Context.Queryable<Admin.NET.Application.Collector>()
					where (long?)u.Id == device.CollectorId
					select u).FirstAsync();
				if (collector == null)
				{
					throw Oops.Oh(ErrorCodeEnum.xg1002);
				}
				if (collector.Status == 0)
				{
					throw Oops.Oh(ErrorCodeEnumEx.X1003);
				}
				imei = collector.Imei;
			}
			if (!TenantId.HasValue)
			{
				TenantId = long.Parse(App.User.FindFirst("TenantId").Value);
			}
			var (pluginService, currentModel) = AggrementPluginUtil.GetPlugin(device, isdtu);
			if (currentModel.HasGate == 0 || string.IsNullOrWhiteSpace(currentModel.PowerOffCMD) || string.IsNullOrWhiteSpace(currentModel.PowerOnCMD))
			{
				throw Oops.Oh("当前电表不支持拉合闸");
			}
			if (input.GateStatus == 1)
			{
				pluginService.PowerOff(imei, device.LowAddr, currentModel.Code, currentModel.PowerOffCMD);
			}
			else
			{
				pluginService.PowerOn(imei, device.LowAddr, currentModel.Code, currentModel.PowerOnCMD);
			}
			int code = ((device.GateStatus == 0) ? 1 : 0);
			await (from u in _rep.Context.Updateable<ElectricMeter>().SetColumns((ElectricMeter u) => u.GateStatus == code).SetColumns((ElectricMeter u) => u.SignalStatus == 1)
				where u.Id == device.Id
				select u).ExecuteCommandAsync();
			long orgId = 0L;
			long.TryParse(App.User?.FindFirst("OrgId")?.Value, out orgId);
			long userId = 0L;
			long.TryParse(App.User?.FindFirst("UserId")?.Value, out userId);
			string value = JsonConvert.SerializeObject(input);
			OperationLog operationLog = new OperationLog
			{
				OrgId = orgId,
				OrgName = App.User?.FindFirst("OrgName")?.Value,
				RealName = App.User?.FindFirst("RealName")?.Value,
				UserId = userId,
				IsDelete = false,
				Data = value,
				TenantId = TenantId,
				OperaId = device.Id,
				OperatName = "拉合闸",
				Operat = "name"
			};
			await _rep.Context.Insertable(operationLog).ExecuteCommandAsync();
			if (!device.RoomId.HasValue)
			{
				return;
			}
			Room room = await (from w in _rep.Context.Queryable<Room>()
				where w.TenantId == TenantId && (long?)w.Id == device.RoomId
				select w).FirstAsync();
			if (room == null || !room.OwnerId.HasValue)
			{
				return;
			}
			Owner owner = await (from w in _rep.Context.Queryable<Owner>()
				where w.TenantId == TenantId && (long?)w.Id == room.OwnerId
				select new Owner
				{
					Email = w.Email,
					Id = w.Id,
					AppId = w.AppId,
					OpenId = w.OpenId,
					PhoneNumber = w.PhoneNumber,
					Name = w.Name
				}).FirstAsync();
			if (owner != null)
			{
				string gatename = ((input.GateStatus == 1) ? "断闸" : "合闸");
				BillNoticePayload billNoticePayload = new BillNoticePayload
				{
					Body = $"您的电表：{device.Name}({device.Sn})已{gatename}。",
					Subject = "电表" + gatename,
					GateStatus = input.GateStatus,
					Owners = new List<Owner> { owner },
					MeterName = device.Name,
					RoomId = room.Id,
					RoomName = room.Name,
					Path = "/userPage/meterDetail/meterDetail?meterId=" + device.Id
				};
				EventPayload payload = new EventPayload
				{
					Data = JsonConvert.SerializeObject(billNoticePayload),
					TenantId = TenantId.Value
				};
				for (int i = 0; i < 4; i++)
				{
					_eventPublisher.PublishAsync($"{i}:SendGateNotice", payload).Wait();
				}
			}
			return;
		}
		throw Oops.Oh(ErrorCodeEnum.xg1002);
	}

	/// <summary>
	/// 分页查询电表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/electricity/page")]
	public async Task<dynamic> Page([FromQuery] ElectricMeteInput input)
	{
		ISugarQueryable<ElectricMeter> query = _rep.Context.Queryable<ElectricMeter>().WhereIF(!string.IsNullOrWhiteSpace(input.Name), (ElectricMeter u) => u.Name.Contains(input.Name.Trim())).WhereIF(!string.IsNullOrWhiteSpace(input.Sn), (ElectricMeter u) => u.Sn.Contains(input.Sn.Trim()))
			.WhereIF(input.SignalStatus.HasValue, (ElectricMeter u) => (int?)u.SignalStatus == input.SignalStatus)
			.WhereIF(input.GateStatus.HasValue, (ElectricMeter u) => (int?)u.GateStatus == input.GateStatus)
			.WhereIF(input.IssuedStatus.HasValue, (ElectricMeter u) => (int?)u.IssuedStatus == input.IssuedStatus)
			.WhereIF(input.BuildingId.HasValue, (ElectricMeter u) => u.BuildingId == input.BuildingId)
			.WhereIF(input.RoomId.HasValue, (ElectricMeter u) => u.RoomId == input.RoomId)
			.WhereIF(input.ProtocolType.HasValue, (ElectricMeter u) => (int?)u.ProtocolType == input.ProtocolType)
			.WhereIF(input.PriceRuleId.HasValue, (ElectricMeter u) => u.PriceRuleId == input.PriceRuleId)
			.WhereIF(input.IsPublicMeter.HasValue, (ElectricMeter u) => (bool?)u.IsPublicMeter == input.IsPublicMeter)
			.WhereIF(input.IsElectricityProtection.HasValue, (ElectricMeter u) => (bool?)u.IsElectricityProtection == input.IsElectricityProtection)
			.WhereIF(input.OwnerControl.HasValue, (ElectricMeter u) => (bool?)u.OwnerControl == input.OwnerControl)
			.WhereIF(input.IsSubsidy.HasValue, (ElectricMeter u) => (int?)u.IsSubsidy == input.IsSubsidy)
			.WhereIF(input.LabelId.HasValue, (ElectricMeter u) => u.LabelId == input.LabelId);
		ISugarQueryable<MeterOutPut> info = (from u in query
			select new MeterOutPut
			{
				SignalStatus = u.SignalStatus,
				Sn = u.Sn,
				CombinedActiveSharpElectricEnergy = u.CombinedActiveSharpElectricEnergy,
				GateStatus = u.GateStatus,
				Addr = u.Addr,
				CollectorId = u.CollectorId,
				CombinedActiveFlatElectricEnergy = u.CombinedActiveFlatElectricEnergy,
				CombinedActivePeakElectricEnergy = u.CombinedActivePeakElectricEnergy,
				CombinedActiveTotalElectricEnergy = u.CombinedActiveTotalElectricEnergy,
				CombinedActiveValleyElectricEnergy = u.CombinedActiveValleyElectricEnergy,
				TenantId = u.TenantId,
				CreateTime = u.CreateTime,
				CreateUserId = u.CreateUserId,
				Id = u.Id,
				IsDelete = u.IsDelete,
				Multiplier = u.Multiplier,
				Name = u.Name,
				PriceRuleId = u.PriceRuleId,
				PriceName = from s4 in SqlFunc.Subqueryable<ElectricityPriceRule>()
					where (long?)s4.Id == u.PriceRuleId
					select s4.Name,
				ProtocolType = u.ProtocolType,
				RoomId = u.RoomId,
				RoomName = from s3 in SqlFunc.Subqueryable<Room>()
					where (long?)s3.Id == u.RoomId
					select s3.Name,
				BuildingId = u.BuildingId,
				BuildingName = from s6 in SqlFunc.Subqueryable<Building>()
					where (long?)s6.Id == u.BuildingId
					select s6.Name,
				UpdateTime = u.UpdateTime,
				UpdateUserId = u.UpdateUserId,
				IssuedStatus = u.IssuedStatus,
				LowAddr = u.LowAddr,
				LabelId = u.LabelId,
				IsPublicMeter = u.IsPublicMeter,
				LabelName = from s5 in SqlFunc.Subqueryable<LabelManagement>()
					where (long?)s5.Id == u.LabelId
					select s5.Name,
				ElectricityProtectionBegin = u.ElectricityProtectionBegin,
				ElectricityProtectionEnd = u.ElectricityProtectionEnd,
				IsElectricityProtection = u.IsElectricityProtection,
				LatestMeterReadingTime = u.LatestMeterReadingTime,
				Latitude = u.Latitude,
				Longitude = u.Longitude,
				OwnerControl = u.OwnerControl,
				IsSubsidy = u.IsSubsidy,
				SubsidyFee = u.SubsidyFee,
				NowSubsidyFee = u.NowSubsidyFee,
				ReservationSubsidyFee = u.ReservationSubsidyFee,
				SubsidyTime = u.SubsidyTime,
				ReservationSubsidyTime = u.ReservationSubsidyTime,
				BaseCombinedActiveFlatElectricEnergy = u.BaseCombinedActiveFlatElectricEnergy,
				BaseCombinedActivePeakElectricEnergy = u.BaseCombinedActivePeakElectricEnergy,
				BaseCombinedActiveSharpElectricEnergy = u.BaseCombinedActiveSharpElectricEnergy,
				BaseCombinedActiveTotalElectricEnergy = u.BaseCombinedActiveTotalElectricEnergy,
				BaseCombinedActiveValleyElectricEnergy = u.BaseCombinedActiveValleyElectricEnergy,
				BaseCombinedActiveValleyDeepElectricEnergy = u.BaseCombinedActiveValleyDeepElectricEnergy,
				ElectricityLossPercentage = u.ElectricityLossPercentage,
				RSSI = u.RSSI,
				LastOnlineTime = u.LastOnlineTime,
				BrandId = u.BrandId
			} into u
			orderby u.CreateTime descending
			select u).OrderBuilder(input);
		return await info.ToPagedListAsync(input.Page, input.PageSize);
	}

	/// <summary>
	/// 分页查询电表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/electricity/pageapp")]
	public async Task<dynamic> PageApp([FromQuery] ElectricMeteInput input)
	{
		List<long> roomIds = new List<long>();
		if (input.IsArrears.HasValue)
		{
			if (input.IsArrears == 0)
			{
				roomIds = await (from u in _repRoom.AsQueryable()
					where u.Balance <= 50m && u.Balance >= 0m
					select u.Id).ToListAsync();
			}
			else
			{
				roomIds = await (from u in _repRoom.AsQueryable()
					where u.Balance < 0m
					select u.Id).ToListAsync();
			}
		}
		ISugarQueryable<ElectricMeter> query = _rep.Context.Queryable<ElectricMeter>().WhereIF(!string.IsNullOrWhiteSpace(input.Name), (ElectricMeter u) => u.Name.Contains(input.Name.Trim()) || u.Sn.Contains(input.Name.Trim())).WhereIF(input.SignalStatus.HasValue, (ElectricMeter u) => (int?)u.SignalStatus == input.SignalStatus)
			.WhereIF(input.GateStatus.HasValue, (ElectricMeter u) => u.SignalStatus == 1 && (int?)u.GateStatus == input.GateStatus)
			.WhereIF(input.IssuedStatus.HasValue, (ElectricMeter u) => (int?)u.IssuedStatus == input.IssuedStatus)
			.WhereIF(input.BuildingId.HasValue, (ElectricMeter u) => u.BuildingId == input.BuildingId)
			.WhereIF(input.RoomId.HasValue, (ElectricMeter u) => u.RoomId == input.RoomId)
			.WhereIF(input.ProtocolType.HasValue, (ElectricMeter u) => (int?)u.ProtocolType == input.ProtocolType)
			.WhereIF(input.PriceRuleId.HasValue, (ElectricMeter u) => u.PriceRuleId == input.PriceRuleId)
			.WhereIF(input.IsPublicMeter.HasValue, (ElectricMeter u) => (bool?)u.IsPublicMeter == input.IsPublicMeter)
			.WhereIF(input.IsElectricityProtection.HasValue, (ElectricMeter u) => (bool?)u.IsElectricityProtection == input.IsElectricityProtection)
			.WhereIF(input.OwnerControl.HasValue, (ElectricMeter u) => (bool?)u.OwnerControl == input.OwnerControl)
			.WhereIF(input.IsSubsidy.HasValue, (ElectricMeter u) => (int?)u.IsSubsidy == input.IsSubsidy)
			.WhereIF(input.IsArrears.HasValue, (ElectricMeter u) => roomIds.Contains(u.RoomId.Value));
		ISugarQueryable<MeterOutPut> info = (from u in query
			select new MeterOutPut
			{
				SignalStatus = u.SignalStatus,
				Sn = u.Sn,
				CombinedActiveSharpElectricEnergy = u.CombinedActiveSharpElectricEnergy,
				GateStatus = u.GateStatus,
				Addr = u.Addr,
				CollectorId = u.CollectorId,
				CombinedActiveFlatElectricEnergy = u.CombinedActiveFlatElectricEnergy,
				CombinedActivePeakElectricEnergy = u.CombinedActivePeakElectricEnergy,
				CombinedActiveTotalElectricEnergy = u.CombinedActiveTotalElectricEnergy,
				CombinedActiveValleyElectricEnergy = u.CombinedActiveValleyElectricEnergy,
				TenantId = u.TenantId,
				CreateTime = u.CreateTime,
				CreateUserId = u.CreateUserId,
				Id = u.Id,
				IsDelete = u.IsDelete,
				Multiplier = u.Multiplier,
				Name = u.Name,
				PriceRuleId = u.PriceRuleId,
				PriceInfo = (from s4 in SqlFunc.Subqueryable<ElectricityPriceRule>()
					where (long?)s4.Id == u.PriceRuleId
					select s4).First(),
				ProtocolType = u.ProtocolType,
				RoomId = u.RoomId,
				RoomInfo = (from s3 in SqlFunc.Subqueryable<Room>()
					where (long?)s3.Id == u.RoomId
					select s3).First(),
				BuildingId = u.BuildingId,
				BuildingName = from s6 in SqlFunc.Subqueryable<Building>()
					where (long?)s6.Id == u.BuildingId
					select s6.Name,
				UpdateTime = u.UpdateTime,
				UpdateUserId = u.UpdateUserId,
				IssuedStatus = u.IssuedStatus,
				LowAddr = u.LowAddr,
				LabelId = u.LabelId,
				IsPublicMeter = u.IsPublicMeter,
				LabelName = from s5 in SqlFunc.Subqueryable<LabelManagement>()
					where (long?)s5.Id == u.LabelId
					select s5.Name,
				ElectricityProtectionBegin = u.ElectricityProtectionBegin,
				ElectricityProtectionEnd = u.ElectricityProtectionEnd,
				IsElectricityProtection = u.IsElectricityProtection,
				LatestMeterReadingTime = u.LatestMeterReadingTime,
				Latitude = u.Latitude,
				Longitude = u.Longitude,
				OwnerControl = u.OwnerControl,
				IsSubsidy = u.IsSubsidy,
				SubsidyFee = u.SubsidyFee,
				NowSubsidyFee = u.NowSubsidyFee,
				ReservationSubsidyFee = u.ReservationSubsidyFee,
				SubsidyTime = u.SubsidyTime,
				ReservationSubsidyTime = u.ReservationSubsidyTime,
				BaseCombinedActiveFlatElectricEnergy = u.BaseCombinedActiveFlatElectricEnergy,
				BaseCombinedActivePeakElectricEnergy = u.BaseCombinedActivePeakElectricEnergy,
				BaseCombinedActiveSharpElectricEnergy = u.BaseCombinedActiveSharpElectricEnergy,
				BaseCombinedActiveTotalElectricEnergy = u.BaseCombinedActiveTotalElectricEnergy,
				BaseCombinedActiveValleyElectricEnergy = u.BaseCombinedActiveValleyElectricEnergy,
				BaseCombinedActiveValleyDeepElectricEnergy = u.BaseCombinedActiveValleyDeepElectricEnergy,
				ElectricityLossPercentage = u.ElectricityLossPercentage,
				RSSI = u.RSSI,
				LastOnlineTime = u.LastOnlineTime,
				BrandId = u.BrandId
			} into u
			orderby u.CreateTime descending
			select u).OrderBuilder(input);
		SqlSugarPagedList<MeterOutPut> model = await info.ToPagedListAsync(input.Page, input.PageSize);
		List<Room> roomInfo = (from u in model.Items
			where u.RoomInfo != null
			select u.RoomInfo).Distinct().ToList();
		List<long?> ownerId = (from u in roomInfo
			where u.OwnerId.HasValue
			select u.OwnerId).Distinct().ToList();
		List<Owner> owner = await (from u in _rep.Context.Queryable<Owner>()
			where ownerId.Contains(u.Id)
			select u).ToListAsync();
		model.Items.ToList().ForEach(delegate(MeterOutPut u)
		{
			Owner owner2 = owner.Where((Owner s) => s.Id == u.RoomInfo?.OwnerId).FirstOrDefault();
			if (owner2 != null)
			{
				u.UserId = owner2.Id;
				u.UserName = owner2.Name;
				u.UserPhone = owner2.PhoneNumber;
			}
			u.RoomName = u.RoomInfo?.Name;
		});
		return model;
	}

	[HttpPost("/electricity/execl")]
	public async Task<IActionResult> ExportMeter([FromBody] ElectricMeteInput input)
	{
		string str = "电表信息-" + DateTime.Now.ToString("yyyy-MM-dd_HH_mm_ss");
		List<string> column = new List<string>();
		List<string> title = new List<string>();
		ISugarQueryable<ElectricMeter> query = _rep.Context.Queryable<ElectricMeter>().WhereIF(!string.IsNullOrWhiteSpace(input.Name), (ElectricMeter u) => u.Name.Contains(input.Name.Trim())).WhereIF(!string.IsNullOrWhiteSpace(input.Sn), (ElectricMeter u) => u.Sn.Contains(input.Sn.Trim()))
			.WhereIF(input.SignalStatus.HasValue, (ElectricMeter u) => (int?)u.SignalStatus == input.SignalStatus)
			.WhereIF(input.GateStatus.HasValue, (ElectricMeter u) => (int?)u.GateStatus == input.GateStatus)
			.WhereIF(input.IssuedStatus.HasValue, (ElectricMeter u) => (int?)u.IssuedStatus == input.IssuedStatus);
		List<MtertExcel> info = await (from u in query
			select new MtertExcel
			{
				SignalStatus = u.SignalStatus,
				Sn = u.Sn,
				GateStatus = u.GateStatus,
				Addr = u.Addr,
				CreateTime = u.CreateTime,
				CreateUserId = u.CreateUserId,
				Multiplier = u.Multiplier,
				Name = u.Name,
				PriceRuleId = u.PriceRuleId,
				PriceName = from s4 in SqlFunc.Subqueryable<ElectricityPriceRule>()
					where (long?)s4.Id == u.PriceRuleId
					select s4.Name,
				ProtocolType = u.ProtocolType,
				RoomId = u.RoomId,
				RoomName = from s3 in SqlFunc.Subqueryable<Room>()
					where (long?)s3.Id == u.RoomId
					select s3.Name,
				UpdateTime = u.UpdateTime,
				UpdateUserId = u.UpdateUserId,
				IssuedStatus = u.IssuedStatus,
				LowAddr = u.LowAddr,
				LabelId = u.LabelId,
				IsPublicMeter = u.IsPublicMeter,
				LabelName = from s5 in SqlFunc.Subqueryable<LabelManagement>()
					where (long?)s5.Id == u.LabelId
					select s5.Name,
				BaseCombinedActiveTotalElectricEnergy = u.BaseCombinedActiveTotalElectricEnergy,
				BaseCombinedActiveSharpElectricEnergy = u.BaseCombinedActiveSharpElectricEnergy,
				BaseCombinedActivePeakElectricEnergy = u.BaseCombinedActivePeakElectricEnergy,
				BaseCombinedActiveFlatElectricEnergy = u.BaseCombinedActiveFlatElectricEnergy,
				BaseCombinedActiveValleyElectricEnergy = u.BaseCombinedActiveValleyElectricEnergy,
				BaseCombinedActiveValleyDeepElectricEnergy = u.BaseCombinedActiveValleyDeepElectricEnergy,
				CombinedActiveTotalElectricEnergy = u.CombinedActiveTotalElectricEnergy,
				CombinedActiveSharpElectricEnergy = u.CombinedActiveSharpElectricEnergy,
				CombinedActivePeakElectricEnergy = u.CombinedActivePeakElectricEnergy,
				CombinedActiveFlatElectricEnergy = u.CombinedActiveFlatElectricEnergy,
				CombinedActiveValleyElectricEnergy = u.CombinedActiveValleyElectricEnergy,
				LatestMeterReadingTime = u.LatestMeterReadingTime
			} into u
			orderby u.SignalStatus descending
			select u).OrderBuilder(input).ToListAsync();
		column.AddRange(new string[21]
		{
			"Sn", "Name", "LabelName", "Addr", "GateStatusName", "Multiplier", "PriceName", "RoomName", "IssuedStatusName", "CombinedActiveTotalElectricEnergy",
			"CombinedActiveSharpElectricEnergy", "CombinedActivePeakElectricEnergy", "CombinedActiveFlatElectricEnergy", "CombinedActiveValleyElectricEnergy", "BaseCombinedActiveTotalElectricEnergy", "BaseCombinedActiveSharpElectricEnergy", "BaseCombinedActivePeakElectricEnergy", "BaseCombinedActiveFlatElectricEnergy", "BaseCombinedActiveValleyElectricEnergy", "LatestMeterReadingTime",
			"CreateTime"
		});
		title.AddRange(new string[21]
		{
			"设备编号", "设备名称", "标签", "表地址", "电闸状态", "倍率", "电价方案", "房间名称", "下发状态", "组合有功电能(总)",
			"组合有功电能(尖)", "组合有功电能(峰)", "组合有功电能(平)", "组合有功电能(谷)", "起始组合有功电能(总)", "起始组合有功电能(尖)", "起始组合有功电能(峰)", "起始组合有功电能(平)", "起始组合有功电能(谷)", "抄表时间",
			"创建日期"
		});
		MemoryStream memery = ExportToExcel.ExportToList(info.ToArray(), str, str, column.ToArray(), title.ToArray());
		App.HttpContext.Response.ContentType = "application/vnd.ms-excel";
		byte[] aa = memery.ToArray();
		return new FileStreamResult(new MemoryStream(aa), "application/octet-stream")
		{
			FileDownloadName = str + ".xlsx"
		};
	}

	/// <summary>
	/// 导出列表excel
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/templeteexcel")]
	public async Task<IActionResult> Templeteexcel()
	{
		string str = "电表模板-" + DateTime.Now.ToString("yyyy-MM-dd");
		List<string> list = new List<string>
		{
			"品牌型号", "表序列号", "表名称", "表地址站号", "付费方案", "标签", "协议类型", "倍率", "所属房间", "电损率%",
			"起始组合电能(总)", "起始组合电能(尖)", "起始组合电能(峰)", "起始组合电能(平)", "起始组合电能(谷)"
		};
		Dictionary<string, List<string>> dic = new Dictionary<string, List<string>> { 
		{
			"协议类型",
			new List<string> { "4G", "网关" }
		} };
		List<string> info = (await (from u in _rep.Context.Queryable<ElectricityPriceRule>()
			select new { u.Name, u.Id }).ToListAsync()).Select(u => u.Name + "[" + u.Id + "]").ToList();
		List<string> lableinfo = (await (from u in _rep.Context.Queryable<LabelManagement>()
			select new { u.Name, u.Id }).ToListAsync()).Select(u => u.Name + "[" + u.Id + "]").ToList();
		dic.Add("付费方案", info);
		dic.Add("标签", lableinfo);
		List<RoomBuildOutput> infoRoom = await (from u in _rep.Context.Queryable<Room>()
			select new RoomBuildOutput
			{
				Id = u.BuildingId,
				Label = u.Name,
				Value = u.Id
			} into u
			orderby u.Id
			select u).ToListAsync();
		List<string> room = new List<string>();
		foreach (RoomBuildOutput item in infoRoom)
		{
			room.Add($"{item.Label}[{item.Value}]");
		}
		dic.Add("所属房间", room);
		long tenantId = Convert.ToInt64(App.User?.FindFirst("TenantId")?.Value);
		var brandmodel = await (from l in _rep.Context.Queryable<TenantBrandModel>().LeftJoin((TenantBrandModel l, BrandModel r) => l.BrandId == r.Id)
			where l.Type == 0 && l.TenantId == tenantId
			select l).Select((TenantBrandModel l, BrandModel r) => new
		{
			label = r.Name,
			value = l.BrandId
		}).ToListAsync();
		List<string> models = new List<string>();
		foreach (var item in brandmodel)
		{
			models.Add($"{item.label}[{item.value}]");
		}
		dic.Add("品牌型号", models);
		ExcelUtil excelUtil = new ExcelUtil();
		MemoryStream stream = excelUtil.GetTemplate(list, dic, str);
		return new FileStreamResult(new MemoryStream(stream.ToArray()), "application/octet-stream")
		{
			FileDownloadName = str + ".xlsx"
		};
	}

	/// <summary>
	/// 上传文件
	/// </summary>
	/// <param name="file"></param>
	/// <param name="path"></param>
	/// <returns></returns>
	[HttpPost("/electricity/uploadpdf")]
	public async Task UploadFile([Required] IFormFile file, string path = "")
	{
		try
		{
			ExcelUtil excelUtil = new ExcelUtil();
			List<AddExcelElectricMeterInput> list = excelUtil.ExcelToList<AddExcelElectricMeterInput>(file, new Dictionary<string, string>
			{
				{ "品牌型号", "BrandName" },
				{ "表序列号", "Sn" },
				{ "表名称", "Name" },
				{ "表地址站号", "Addr" },
				{ "付费方案", "PriceRule" },
				{ "标签", "LableInfo" },
				{ "协议类型", "ProtocolType" },
				{ "倍率", "Multiplier" },
				{ "所属房间", "Room" },
				{ "电损率%", "ElectricityLossPercentage" },
				{ "起始组合电能(总)", "BaseCombinedActiveTotalElectricEnergy" },
				{ "起始组合电能(尖)", "BaseCombinedActiveSharpElectricEnergy" },
				{ "起始组合电能(峰)", "BaseCombinedActivePeakElectricEnergy" },
				{ "起始组合电能(平)", "BaseCombinedActiveFlatElectricEnergy" },
				{ "起始组合电能(谷)", "BaseCombinedActiveValleyElectricEnergy" }
			});
			if (list.Count == 0)
			{
				throw Oops.Bah("当前导入数据不完整");
			}
			List<string> imeilist = list.Select((AddExcelElectricMeterInput i) => i.Sn).ToList();
			ElectricMeter eleModel = await (from u in _rep.Context.Queryable<ElectricMeter>().ClearFilter()
				where imeilist.Contains(u.Sn)
				select u).FirstAsync();
			if (eleModel != null)
			{
				throw Oops.Oh("当前表序列号已存在" + eleModel.Sn);
			}
			string disImei = (from u in imeilist
				group u by u into u
				select new
				{
					count = u.Count(),
					sn = u.Key
				} into u
				where u.count > 1
				select u).FirstOrDefault()?.sn;
			if (!string.IsNullOrEmpty(disImei))
			{
				throw Oops.Oh("当前表序列号存在重复" + disImei);
			}
			List<AddElectricMeterInput> listadd = new List<AddElectricMeterInput>();
			await GetExeleModel(list, listadd);
			List<ElectricMeter> addInfo = listadd.Adapt<List<ElectricMeter>>();
			long tenantId = Convert.ToInt64(App.User?.FindFirst("TenantId")?.Value);
			SysTenant tenantInfo = await (from u in _rep.Context.Queryable<SysTenant>()
				where u.Id == tenantId
				select u).FirstAsync();
			await _rep.Context.Ado.BeginTranAsync();
			int count = addInfo.Count();
			if (tenantInfo?.IsSubscribe ?? false)
			{
				if (tenantInfo.AllVolume <= tenantInfo.UseVolume + count)
				{
					throw Oops.Oh("当前容量不足，请联系管理员");
				}
				await (from u in _rep.Context.Updateable<SysTenant>().SetColumns((SysTenant u) => u.UseVolume == u.UseVolume + count)
					where u.Id == tenantId
					select u).ExecuteCommandAsync();
			}
			List<long?> roomIds = addInfo.Select((ElectricMeter s) => s.RoomId).Distinct().ToList();
			var allroom = await (from u in _rep.Context.Queryable<Room>()
				where roomIds.Contains(u.Id)
				select new { u.Id, u.BuildingId }).ToListAsync();
			foreach (ElectricMeter item in addInfo)
			{
				if (item.RoomId.HasValue)
				{
					item.BuildingId = allroom.Where(w => w.Id == item.RoomId).FirstOrDefault()?.BuildingId;
				}
				item.GateStatus = 1;
			}
			_rep.InsertRange(addInfo.ToArray());
			await _rep.Context.Ado.CommitTranAsync();
		}
		catch (Exception ex)
		{
			await _rep.Context.Ado.RollbackTranAsync();
			if (!(ex is Exception source))
			{
				throw ex;
			}
			ExceptionDispatchInfo.Capture(source).Throw();
		}
	}

	private string LowAddr(string addr)
	{
		if (addr.Length == 0 || addr.Length % 2 != 0)
		{
			return "";
		}
		List<string> arr = new List<string>();
		int slength = addr.Length / 2;
		for (int i = 0; i < slength; i++)
		{
			arr.Add(addr.Substring(i * 2, 2));
		}
		string resultvalue = "";
		for (int i = slength - 1; i >= 0; i--)
		{
			resultvalue += arr[i];
		}
		return resultvalue;
	}

	private async Task GetExeleModel(List<AddExcelElectricMeterInput> list, List<AddElectricMeterInput> listadd)
	{
		List<long> priceRuleId = await (from u in _rep.Context.Queryable<ElectricityPriceRule>()
			select u.Id).ToListAsync();
		List<long> roomId = await (from u in _rep.Context.Queryable<Room>()
			where u.BuildingId != 0
			select u.Id).ToListAsync();
		List<long> lableId = await (from u in _rep.Context.Queryable<LabelManagement>()
			select u.Id).ToListAsync();
		long tenantId = Convert.ToInt64(App.User?.FindFirst("TenantId")?.Value);
		await (from l in _rep.Context.Queryable<TenantBrandModel>().LeftJoin((TenantBrandModel l, BrandModel r) => l.BrandId == r.Id)
			where l.Type == 0 && l.TenantId == tenantId
			select l).Select((TenantBrandModel l, BrandModel r) => l.BrandId).ToListAsync();
		foreach (AddExcelElectricMeterInput item in list)
		{
			AddElectricMeterInput addElectricMeterInput = new AddElectricMeterInput
			{
				Multiplier = item.Multiplier
			};
			if (string.IsNullOrEmpty(item.Name))
			{
				throw Oops.Oh("当前表名称不能为空" + item.Sn);
			}
			addElectricMeterInput.Name = item.Name;
			if (string.IsNullOrEmpty(item.Addr))
			{
				throw Oops.Oh("当前表地址不能为空" + item.Sn);
			}
			addElectricMeterInput.Addr = item.Addr;
			addElectricMeterInput.LowAddr = LowAddr(item.Addr);
			if (string.IsNullOrEmpty(item.Sn))
			{
				throw Oops.Oh("当前表序列号不能为空" + item.Sn);
			}
			addElectricMeterInput.Sn = item.Sn;
			if (string.IsNullOrEmpty(item.ProtocolType))
			{
				throw Oops.Oh("当前表类型不能为空" + item.Sn);
			}
			if (item.ProtocolType.Trim() == "4G")
			{
				addElectricMeterInput.ProtocolType = 0;
			}
			else
			{
				if (!(item.ProtocolType.Trim() == "网关"))
				{
					throw Oops.Oh("当前表类型不存在请假查" + item.Sn);
				}
				addElectricMeterInput.ProtocolType = 1;
			}
			string pattern = "\\[(\\d+)\\]";
			if (!string.IsNullOrWhiteSpace(item.BrandName))
			{
				Match match = Regex.Match(item.BrandName, pattern);
				if (match.Success)
				{
					string id = match.Groups[1].Value;
					long brandid = Convert.ToInt64(id);
					addElectricMeterInput.BrandId = brandid;
					if (!string.IsNullOrEmpty(item.PriceRule))
					{
						match = Regex.Match(item.PriceRule, pattern);
						if (match.Success)
						{
							id = match.Groups[1].Value;
							long priceId = Convert.ToInt64(id);
							addElectricMeterInput.PriceRuleId = (priceRuleId.Contains(priceId) ? new long?(priceId) : null);
						}
					}
					if (!string.IsNullOrEmpty(item.Room))
					{
						match = Regex.Match(item.Room, pattern);
						if (match.Success)
						{
							id = match.Groups[1].Value;
							long roomid = Convert.ToInt64(id);
							addElectricMeterInput.RoomId = (roomId.Contains(roomid) ? new long?(roomid) : null);
						}
					}
					if (!string.IsNullOrEmpty(item.LableInfo))
					{
						match = Regex.Match(item.LableInfo, pattern);
						if (match.Success)
						{
							id = match.Groups[1].Value;
							long lableid = Convert.ToInt64(id);
							addElectricMeterInput.LabelId = (lableId.Contains(lableid) ? new long?(lableid) : null);
						}
					}
					addElectricMeterInput.ElectricityLossPercentage = item.ElectricityLossPercentage;
					addElectricMeterInput.BaseCombinedActiveFlatElectricEnergy = item.BaseCombinedActiveFlatElectricEnergy;
					addElectricMeterInput.BaseCombinedActivePeakElectricEnergy = item.BaseCombinedActivePeakElectricEnergy;
					addElectricMeterInput.BaseCombinedActiveSharpElectricEnergy = item.BaseCombinedActiveSharpElectricEnergy;
					addElectricMeterInput.BaseCombinedActiveTotalElectricEnergy = item.BaseCombinedActiveTotalElectricEnergy;
					addElectricMeterInput.BaseCombinedActiveValleyElectricEnergy = item.BaseCombinedActiveValleyElectricEnergy;
					listadd.Add(addElectricMeterInput);
					continue;
				}
				throw Oops.Bah("品牌型号填写不合规:" + item.BrandName);
			}
			throw Oops.Bah("请填写品牌型号");
		}
	}

	/// <summary>
	/// 增加电表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/add")]
	public async Task Add(AddElectricMeterInput input)
	{
		try
		{
			ElectricMeter entity = input.Adapt<ElectricMeter>();
			entity.CombinedActiveFlatElectricEnergy = input.BaseCombinedActiveFlatElectricEnergy;
			entity.CombinedActivePeakElectricEnergy = input.BaseCombinedActivePeakElectricEnergy;
			entity.CombinedActiveSharpElectricEnergy = input.BaseCombinedActiveSharpElectricEnergy;
			entity.CombinedActiveTotalElectricEnergy = input.BaseCombinedActiveTotalElectricEnergy;
			entity.CombinedActiveValleyElectricEnergy = input.BaseCombinedActiveValleyElectricEnergy;
			if (await _rep.Context.Queryable<ElectricMeter>().ClearFilter().AnyAsync((ElectricMeter u) => u.Sn == entity.Sn))
			{
				throw Oops.Oh(ErrorCodeEnum.R2002);
			}
			EWarehousing model = await (from u in _rep.Context.Queryable<EWarehousing>().ClearFilter()
				where u.Sn == input.Sn
				select u).FirstAsync();
			if (model == null)
			{
				throw Oops.Oh("当前设备库存不存在请联系管理员");
			}
			entity.Addr = model.Addr;
			entity.BrandId = model.BrandId;
			entity.LowAddr = LowAddr(model.Addr);
			entity.ProtocolType = model.ProtocolType;
			long tenantId = Convert.ToInt64(App.User?.FindFirst("TenantId")?.Value);
			SysTenant tenantInfo = await (from u in _rep.Context.Queryable<SysTenant>()
				where u.Id == tenantId
				select u).FirstAsync();
			await _rep.Context.Ado.BeginTranAsync();
			if (tenantInfo?.IsSubscribe ?? false)
			{
				if (tenantInfo.AllVolume <= tenantInfo.UseVolume + 1)
				{
					throw Oops.Oh("当前容量不足，请联系管理员");
				}
				await (from u in _rep.Context.Updateable<SysTenant>().SetColumns((SysTenant u) => u.UseVolume == u.UseVolume + 1)
					where u.Id == tenantId
					select u).ExecuteCommandAsync();
			}
			entity.GateStatus = 1;
			await _rep.InsertAsync(entity);
			await _rep.Context.Ado.CommitTranAsync();
		}
		catch (Exception ex)
		{
			await _rep.Context.Ado.RollbackTranAsync();
			if (!(ex is Exception source))
			{
				throw ex;
			}
			ExceptionDispatchInfo.Capture(source).Throw();
		}
	}

	/// <summary>
	/// 增加电表APP
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/addapp")]
	public async Task AddApp(AddAppElectricMeterInput input)
	{
		try
		{
			ElectricMeter entity = input.Adapt<ElectricMeter>();
			entity.CombinedActiveFlatElectricEnergy = input.BaseCombinedActiveFlatElectricEnergy;
			entity.CombinedActivePeakElectricEnergy = input.BaseCombinedActivePeakElectricEnergy;
			entity.CombinedActiveSharpElectricEnergy = input.BaseCombinedActiveSharpElectricEnergy;
			entity.CombinedActiveTotalElectricEnergy = input.BaseCombinedActiveTotalElectricEnergy;
			entity.CombinedActiveValleyElectricEnergy = input.BaseCombinedActiveValleyElectricEnergy;
			if (await _rep.Context.Queryable<ElectricMeter>().ClearFilter().AnyAsync((ElectricMeter u) => u.Sn == entity.Sn))
			{
				throw Oops.Oh(ErrorCodeEnum.R2002);
			}
			EWarehousing model = await (from u in _rep.Context.Queryable<EWarehousing>().ClearFilter()
				where u.Sn == input.Sn
				select u).FirstAsync();
			if (model == null)
			{
				throw Oops.Oh("当前设备库存不存在请联系管理员");
			}
			long tenantId = Convert.ToInt64(App.User?.FindFirst("TenantId")?.Value);
			SysTenant tenantInfo = await (from u in _rep.Context.Queryable<SysTenant>()
				where u.Id == tenantId
				select u).FirstAsync();
			await _rep.Context.Ado.BeginTranAsync();
			if (tenantInfo?.IsSubscribe ?? false)
			{
				if (tenantInfo.AllVolume <= tenantInfo.UseVolume + 1)
				{
					throw Oops.Oh("当前容量不足，请联系管理员");
				}
				await (from u in _rep.Context.Updateable<SysTenant>().SetColumns((SysTenant u) => u.UseVolume == u.UseVolume + 1)
					where u.Id == tenantId
					select u).ExecuteCommandAsync();
			}
			if (!input.BuildingId.HasValue && !string.IsNullOrEmpty(input.BuildingName))
			{
				Building building = new Building
				{
					Name = input.BuildingName
				};
				AddAppElectricMeterInput addAppElectricMeterInput = input;
				addAppElectricMeterInput.BuildingId = await _rep.Context.Insertable(building).ExecuteReturnSnowflakeIdAsync();
			}
			if (!input.RoomId.HasValue && !string.IsNullOrEmpty(input.RoomName))
			{
				Room room = new Room
				{
					Name = input.RoomName,
					BuildingId = (input.BuildingId ?? long.MinValue)
				};
				if (!input.OwnerId.HasValue && !string.IsNullOrEmpty(input.Phone))
				{
					if (await (from u in _rep.Context.Queryable<Owner>().ClearFilter()
						where u.PhoneNumber == input.Phone
						select u).FirstAsync() != null)
					{
						await _rep.Context.Ado.RollbackTranAsync();
						throw Oops.Bah("手机号已被使用，请更换手机号");
					}
					Owner owner = new Owner
					{
						Name = input.UserName,
						PhoneNumber = input.Phone,
						Password = MD5Encryption.Encrypt(input.Phone),
						IsEnable = 1
					};
					Room room2 = room;
					room2.OwnerId = await _rep.Context.Insertable(owner).ExecuteReturnSnowflakeIdAsync();
				}
				if (input.OwnerId.HasValue)
				{
					room.OwnerId = input.OwnerId;
				}
				AddAppElectricMeterInput addAppElectricMeterInput2 = input;
				addAppElectricMeterInput2.RoomId = await _rep.Context.Insertable(room).ExecuteReturnSnowflakeIdAsync();
			}
			else if (input.RoomId.HasValue)
			{
				Room roomedit = await (from u in _rep.Context.Queryable<Room>()
					where (long?)u.Id == input.RoomId
					select u).FirstAsync();
				roomedit.BuildingId = input.BuildingId ?? long.MinValue;
				if (!input.OwnerId.HasValue && !string.IsNullOrEmpty(input.Phone))
				{
					if (await (from u in _rep.Context.Queryable<Owner>().ClearFilter()
						where u.PhoneNumber == input.Phone
						select u).FirstAsync() != null)
					{
						await _rep.Context.Ado.RollbackTranAsync();
						throw Oops.Bah("手机号已被使用，请更换手机号");
					}
					Owner owner = new Owner
					{
						Name = input.UserName,
						PhoneNumber = input.Phone,
						Password = MD5Encryption.Encrypt(input.Phone),
						IsEnable = 1
					};
					Room room3 = roomedit;
					room3.OwnerId = await _rep.Context.Insertable(owner).ExecuteReturnSnowflakeIdAsync();
				}
				if (input.OwnerId.HasValue)
				{
					roomedit.OwnerId = input.OwnerId;
				}
				await _rep.Context.Updateable(roomedit).UpdateColumns((Room u) => new { u.BuildingId, u.OwnerId }).ExecuteCommandAsync();
			}
			entity.Addr = model.Addr;
			entity.BrandId = model.BrandId;
			entity.LowAddr = LowAddr(model.Addr);
			entity.ProtocolType = model.ProtocolType;
			entity.RoomId = input.RoomId;
			entity.BuildingId = input.BuildingId;
			entity.GateStatus = 1;
			await _rep.InsertAsync(entity);
			await _rep.Context.Ado.CommitTranAsync();
		}
		catch (Exception ex)
		{
			await _rep.Context.Ado.RollbackTranAsync();
			if (!(ex is Exception source))
			{
				throw ex;
			}
			ExceptionDispatchInfo.Capture(source).Throw();
		}
	}

	/// <summary>
	/// 删除电表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/delete")]
	public async Task Delete(BaseIdInput input)
	{
		try
		{
			ElectricMeter entity = await _rep.GetFirstAsync((ElectricMeter u) => u.Id == input.Id);
			long tenantId = Convert.ToInt64(App.User?.FindFirst("TenantId")?.Value);
			SysTenant tenantInfo = await (from u in _rep.Context.Queryable<SysTenant>()
				where u.Id == tenantId
				select u).FirstAsync();
			await _rep.Context.Ado.BeginTranAsync();
			if (tenantInfo?.IsSubscribe ?? false)
			{
				await (from u in _rep.Context.Updateable<SysTenant>().SetColumns((SysTenant u) => u.UseVolume == u.UseVolume - 1)
					where u.Id == tenantId
					select u).ExecuteCommandAsync();
			}
			DeleteMeter meter = entity.Adapt<DeleteMeter>();
			await _repDel.InsertAsync(meter);
			await _rep.DeleteAsync(entity);
			await _rep.Context.Ado.CommitTranAsync();
		}
		catch (Exception ex)
		{
			await _rep.Context.Ado.RollbackTranAsync();
			if (!(ex is Exception source))
			{
				throw ex;
			}
			ExceptionDispatchInfo.Capture(source).Throw();
		}
	}

	/// <summary>
	/// 批量删除电表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/deleteany")]
	public async Task DeleteAny(List<BaseIdInput> input)
	{
		try
		{
			List<long> ids = input.Select((BaseIdInput u) => u.Id).ToList();
			List<ElectricMeter> entity = await _rep.GetListAsync((ElectricMeter u) => ids.Contains(u.Id));
			long tenantId = Convert.ToInt64(App.User?.FindFirst("TenantId")?.Value);
			SysTenant tenantInfo = await (from u in _rep.Context.Queryable<SysTenant>()
				where u.Id == tenantId
				select u).FirstAsync();
			await _rep.Context.Ado.BeginTranAsync();
			if (tenantInfo?.IsSubscribe ?? false)
			{
				await (from u in _rep.Context.Updateable<SysTenant>().SetColumns((SysTenant u) => u.UseVolume == u.UseVolume - entity.Count)
					where u.Id == tenantId
					select u).ExecuteCommandAsync();
			}
			List<DeleteMeter> meter = entity.Adapt<List<DeleteMeter>>();
			await _repDel.InsertRangeAsync(meter);
			await _rep.DeleteAsync(entity);
			await _rep.Context.Ado.CommitTranAsync();
		}
		catch (Exception ex)
		{
			await _rep.Context.Ado.RollbackTranAsync();
			if (!(ex is Exception source))
			{
				throw ex;
			}
			ExceptionDispatchInfo.Capture(source).Throw();
		}
	}

	/// <summary>
	/// 更新电表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/editapp")]
	[OperationLog("更新电表", "sn")]
	public async Task UpdateApp(UpdateAppElectricityInput input)
	{
		ElectricMeter entity = input.Adapt<ElectricMeter>();
		if (await _rep.IsAnyAsync((ElectricMeter u) => u.Sn == entity.Sn && u.Id != entity.Id))
		{
			throw Oops.Oh(ErrorCodeEnum.R2002);
		}
		ElectricMeter currentMeter = await (from w in _rep.Context.Queryable<ElectricMeter>()
			where w.Id == input.Id
			select w).FirstAsync();
		if (currentMeter == null)
		{
			throw Oops.Bah("当前电表不存在或已被删除，请刷新后重试");
		}
		await _rep.Context.Updateable(entity).UpdateColumns((ElectricMeter u) => new
		{
			u.IsPublicMeter, u.Name, u.Multiplier, u.LabelId, u.Sn, u.ProtocolType, u.Addr, u.PriceRuleId, u.RoomId, u.BuildingId,
			u.LowAddr, u.ElectricityLossPercentage, u.BrandId
		}).ExecuteCommandAsync();
		Room room = await (from u in _rep.Context.Queryable<Room>()
			where u.Id == input.RoomId
			select u).FirstAsync();
		if (!input.UserId.HasValue && !string.IsNullOrEmpty(input.UserPhone))
		{
			if (await (from u in _rep.Context.Queryable<Owner>().ClearFilter()
				where u.PhoneNumber == input.UserPhone
				select u).FirstAsync() != null)
			{
				await _rep.Context.Ado.RollbackTranAsync();
				throw Oops.Bah("手机号已被使用，请更换手机号");
			}
			Owner owner = new Owner
			{
				Name = input.UserName,
				PhoneNumber = input.UserPhone,
				Password = MD5Encryption.Encrypt(input.UserPhone),
				IsEnable = 1
			};
			Room room2 = room;
			room2.OwnerId = await _rep.Context.Insertable(owner).ExecuteReturnSnowflakeIdAsync();
		}
		else if (input.UserId.HasValue)
		{
			room.OwnerId = input.UserId;
		}
		await _rep.Context.Updateable(room).UpdateColumns((Room u) => new { u.OwnerId }).ExecuteCommandAsync();
		decimal? baseCombinedActiveFlatElectricEnergy = currentMeter.BaseCombinedActiveFlatElectricEnergy;
		decimal baseCombinedActiveFlatElectricEnergy2 = input.BaseCombinedActiveFlatElectricEnergy;
		int num;
		if ((baseCombinedActiveFlatElectricEnergy.GetValueOrDefault() == baseCombinedActiveFlatElectricEnergy2) & baseCombinedActiveFlatElectricEnergy.HasValue)
		{
			baseCombinedActiveFlatElectricEnergy = currentMeter.BaseCombinedActivePeakElectricEnergy;
			baseCombinedActiveFlatElectricEnergy2 = input.BaseCombinedActivePeakElectricEnergy;
			if ((baseCombinedActiveFlatElectricEnergy.GetValueOrDefault() == baseCombinedActiveFlatElectricEnergy2) & baseCombinedActiveFlatElectricEnergy.HasValue)
			{
				baseCombinedActiveFlatElectricEnergy = currentMeter.BaseCombinedActiveSharpElectricEnergy;
				baseCombinedActiveFlatElectricEnergy2 = input.BaseCombinedActiveSharpElectricEnergy;
				if ((baseCombinedActiveFlatElectricEnergy.GetValueOrDefault() == baseCombinedActiveFlatElectricEnergy2) & baseCombinedActiveFlatElectricEnergy.HasValue)
				{
					baseCombinedActiveFlatElectricEnergy = currentMeter.BaseCombinedActiveTotalElectricEnergy;
					baseCombinedActiveFlatElectricEnergy2 = input.BaseCombinedActiveTotalElectricEnergy;
					if ((baseCombinedActiveFlatElectricEnergy.GetValueOrDefault() == baseCombinedActiveFlatElectricEnergy2) & baseCombinedActiveFlatElectricEnergy.HasValue)
					{
						baseCombinedActiveFlatElectricEnergy = currentMeter.BaseCombinedActiveValleyElectricEnergy;
						baseCombinedActiveFlatElectricEnergy2 = input.BaseCombinedActiveValleyElectricEnergy;
						if ((baseCombinedActiveFlatElectricEnergy.GetValueOrDefault() == baseCombinedActiveFlatElectricEnergy2) & baseCombinedActiveFlatElectricEnergy.HasValue)
						{
							num = ((!(currentMeter.BaseCombinedActiveValleyDeepElectricEnergy == input.BaseCombinedActiveValleyDeepElectricEnergy)) ? 1 : 0);
							goto IL_0d0d;
						}
					}
				}
			}
		}
		num = 1;
		goto IL_0d0d;
		IL_0d0d:
		if (num != 0)
		{
			if (currentMeter.IsRead || currentMeter.LatestMeterReadingTime.HasValue)
			{
				throw Oops.Bah("因电表已抄表，起始底数修改失败，其他参数保存成功");
			}
			if (await (from u in _rep.Context.Updateable<ElectricMeter>().SetColumns((ElectricMeter u) => new ElectricMeter
				{
					BaseCombinedActiveFlatElectricEnergy = input.BaseCombinedActiveFlatElectricEnergy,
					BaseCombinedActiveSharpElectricEnergy = input.BaseCombinedActiveSharpElectricEnergy,
					BaseCombinedActivePeakElectricEnergy = input.BaseCombinedActivePeakElectricEnergy,
					BaseCombinedActiveTotalElectricEnergy = input.BaseCombinedActiveTotalElectricEnergy,
					BaseCombinedActiveValleyElectricEnergy = input.BaseCombinedActiveValleyElectricEnergy,
					BaseCombinedActiveValleyDeepElectricEnergy = input.BaseCombinedActiveValleyDeepElectricEnergy,
					CombinedActiveFlatElectricEnergy = input.BaseCombinedActiveFlatElectricEnergy,
					CombinedActiveSharpElectricEnergy = input.BaseCombinedActiveSharpElectricEnergy,
					CombinedActivePeakElectricEnergy = input.BaseCombinedActivePeakElectricEnergy,
					CombinedActiveTotalElectricEnergy = input.BaseCombinedActiveTotalElectricEnergy,
					CombinedActiveValleyElectricEnergy = input.BaseCombinedActiveValleyElectricEnergy
				})
				where u.Id == input.Id && u.IsRead == false
				select u).ExecuteCommandAsync() == 0)
			{
				throw Oops.Bah("因电表已抄表，起始底数修改失败，其他参数保存成功");
			}
		}
	}

	/// <summary>
	/// 更新电表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/edit")]
	[OperationLog("更新电表", "sn")]
	public async Task Update(UpdateElectricityInput input)
	{
		ElectricMeter entity = input.Adapt<ElectricMeter>();
		if (await _rep.IsAnyAsync((ElectricMeter u) => u.Sn == entity.Sn && u.Id != entity.Id))
		{
			throw Oops.Oh(ErrorCodeEnum.R2002);
		}
		ElectricMeter currentMeter = await (from w in _rep.Context.Queryable<ElectricMeter>()
			where w.Id == input.Id
			select w).FirstAsync();
		if (currentMeter == null)
		{
			throw Oops.Bah("当前电表不存在或已被删除，请刷新后重试");
		}
		await _rep.Context.Updateable(entity).UpdateColumns((ElectricMeter u) => new
		{
			u.IsPublicMeter, u.Name, u.Multiplier, u.LabelId, u.Sn, u.ProtocolType, u.Addr, u.PriceRuleId, u.RoomId, u.BuildingId,
			u.LowAddr, u.ElectricityLossPercentage, u.BrandId
		}).ExecuteCommandAsync();
		decimal? baseCombinedActiveFlatElectricEnergy = currentMeter.BaseCombinedActiveFlatElectricEnergy;
		decimal baseCombinedActiveFlatElectricEnergy2 = input.BaseCombinedActiveFlatElectricEnergy;
		int num;
		if ((baseCombinedActiveFlatElectricEnergy.GetValueOrDefault() == baseCombinedActiveFlatElectricEnergy2) & baseCombinedActiveFlatElectricEnergy.HasValue)
		{
			baseCombinedActiveFlatElectricEnergy = currentMeter.BaseCombinedActivePeakElectricEnergy;
			baseCombinedActiveFlatElectricEnergy2 = input.BaseCombinedActivePeakElectricEnergy;
			if ((baseCombinedActiveFlatElectricEnergy.GetValueOrDefault() == baseCombinedActiveFlatElectricEnergy2) & baseCombinedActiveFlatElectricEnergy.HasValue)
			{
				baseCombinedActiveFlatElectricEnergy = currentMeter.BaseCombinedActiveSharpElectricEnergy;
				baseCombinedActiveFlatElectricEnergy2 = input.BaseCombinedActiveSharpElectricEnergy;
				if ((baseCombinedActiveFlatElectricEnergy.GetValueOrDefault() == baseCombinedActiveFlatElectricEnergy2) & baseCombinedActiveFlatElectricEnergy.HasValue)
				{
					baseCombinedActiveFlatElectricEnergy = currentMeter.BaseCombinedActiveTotalElectricEnergy;
					baseCombinedActiveFlatElectricEnergy2 = input.BaseCombinedActiveTotalElectricEnergy;
					if ((baseCombinedActiveFlatElectricEnergy.GetValueOrDefault() == baseCombinedActiveFlatElectricEnergy2) & baseCombinedActiveFlatElectricEnergy.HasValue)
					{
						baseCombinedActiveFlatElectricEnergy = currentMeter.BaseCombinedActiveValleyElectricEnergy;
						baseCombinedActiveFlatElectricEnergy2 = input.BaseCombinedActiveValleyElectricEnergy;
						if ((baseCombinedActiveFlatElectricEnergy.GetValueOrDefault() == baseCombinedActiveFlatElectricEnergy2) & baseCombinedActiveFlatElectricEnergy.HasValue)
						{
							num = ((!(currentMeter.BaseCombinedActiveValleyDeepElectricEnergy == input.BaseCombinedActiveValleyDeepElectricEnergy)) ? 1 : 0);
							goto IL_0793;
						}
					}
				}
			}
		}
		num = 1;
		goto IL_0793;
		IL_0793:
		if (num != 0)
		{
			if (currentMeter.IsRead || currentMeter.LatestMeterReadingTime.HasValue)
			{
				throw Oops.Bah("因电表已抄表，起始底数修改失败，其他参数保存成功");
			}
			if (await (from u in _rep.Context.Updateable<ElectricMeter>().SetColumns((ElectricMeter u) => new ElectricMeter
				{
					BaseCombinedActiveFlatElectricEnergy = input.BaseCombinedActiveFlatElectricEnergy,
					BaseCombinedActiveSharpElectricEnergy = input.BaseCombinedActiveSharpElectricEnergy,
					BaseCombinedActivePeakElectricEnergy = input.BaseCombinedActivePeakElectricEnergy,
					BaseCombinedActiveTotalElectricEnergy = input.BaseCombinedActiveTotalElectricEnergy,
					BaseCombinedActiveValleyElectricEnergy = input.BaseCombinedActiveValleyElectricEnergy,
					BaseCombinedActiveValleyDeepElectricEnergy = input.BaseCombinedActiveValleyDeepElectricEnergy,
					CombinedActiveFlatElectricEnergy = input.BaseCombinedActiveFlatElectricEnergy,
					CombinedActiveSharpElectricEnergy = input.BaseCombinedActiveSharpElectricEnergy,
					CombinedActivePeakElectricEnergy = input.BaseCombinedActivePeakElectricEnergy,
					CombinedActiveTotalElectricEnergy = input.BaseCombinedActiveTotalElectricEnergy,
					CombinedActiveValleyElectricEnergy = input.BaseCombinedActiveValleyElectricEnergy
				})
				where u.Id == input.Id && u.IsRead == false
				select u).ExecuteCommandAsync() == 0)
			{
				throw Oops.Bah("因电表已抄表，起始底数修改失败，其他参数保存成功");
			}
		}
	}

	/// <summary>
	/// 获取所有电价
	/// </summary>
	/// <returns></returns>
	[HttpGet("/electricity/getElectricityPrice")]
	public async Task<dynamic> GetElectricityPrice()
	{
		return await (from u in _rep.Context.Queryable<ElectricityPriceRule>()
			select new RoomBuildOutput
			{
				Value = u.Id,
				Label = u.Name
			}).ToListAsync();
	}

	/// <summary>
	/// 获取所有标签
	/// </summary>
	/// <returns></returns>
	[HttpGet("/electricity/labelInfo")]
	public async Task<dynamic> GetElectricitLabelInfo()
	{
		return await (from u in _rep.Context.Queryable<LabelManagement>()
			select new RoomBuildOutput
			{
				Value = u.Id,
				Label = u.Name
			}).ToListAsync();
	}

	/// <summary>
	/// 获取所有房间
	/// </summary>
	/// <returns></returns>
	[HttpGet("/electricity/getRoomAll")]
	public async Task<dynamic> GetRoomInfo()
	{
		List<Building> buildings = await _rep.Context.Queryable<Building>().ToListAsync();
		List<Room> rooms = await _rep.Context.Queryable<Room>().ToListAsync();
		List<RoomBuildOutput> roots = (from w in buildings
			where w.Pid == 0
			select new RoomBuildOutput
			{
				Disabled = false,
				Children = new List<RoomBuildOutput>(),
				Id = w.Id,
				Label = w.Name,
				Value = w.Id
			}).ToList();
		List<long> ids = new List<long>();
		foreach (RoomBuildOutput item in roots)
		{
			MapBuildingAndRoom(item, buildings, rooms, ids);
		}
		return roots;
	}

	private void MapBuildingAndRoom(RoomBuildOutput item, List<Building> buildings, List<Room> rooms, List<long> ids)
	{
		if (ids.Contains(item.Id))
		{
			return;
		}
		ids.Add(item.Id);
		item.Children = new List<RoomBuildOutput>();
		List<RoomBuildOutput> children = (from w in buildings
			where w.Pid == item.Id
			select new RoomBuildOutput
			{
				Disabled = false,
				Children = new List<RoomBuildOutput>(),
				Id = w.Id,
				Label = w.Name,
				Value = w.Id
			}).ToList();
		if (children.Count > 0)
		{
			item.Children.AddRange(children);
			foreach (RoomBuildOutput child in children)
			{
				MapBuildingAndRoom(child, buildings, rooms, ids);
			}
		}
		List<RoomBuildOutput> childrooms = (from w in rooms
			where w.BuildingId == item.Id
			select new RoomBuildOutput
			{
				Disabled = false,
				Children = new List<RoomBuildOutput>(),
				Id = w.Id,
				Label = w.Name,
				Value = w.Id
			}).ToList();
		if (childrooms.Count > 0)
		{
			item.Children.AddRange(childrooms);
		}
		if (children.Count == 0 && childrooms.Count == 0)
		{
			item.Disabled = true;
		}
	}

	/// <summary>
	/// 获取房间里所有的电表，
	/// </summary>
	/// <param name="roomId"></param>
	/// <returns></returns>
	[HttpGet("/electricity/getRoomMeter/{roomId}")]
	public async Task<dynamic> GetRoomMeter(long roomId)
	{
		return await (from w in _rep.AsQueryable()
			where w.RoomId == (long?)roomId
			select w into s
			select new { s.Sn, s.Name }).ToListAsync();
	}

	/// <summary>
	/// 获取房间里所有的电表，
	/// </summary>
	/// <param name="roomId"></param>
	/// <returns></returns>
	[HttpGet("/electricity/getRoomMeterWater/{roomId}")]
	public async Task<dynamic> GetRoomMeterWater(long roomId)
	{
		return await (from w in _rep.Context.Queryable<WaterDevice>()
			where w.RoomId == (long?)roomId
			select w into s
			select new
			{
				Sn = s.Sn,
				Name = s.WaterName
			}).ToListAsync();
	}

	/// <summary>
	/// 保电设置
	/// </summary>
	/// <param name="meterId"></param>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/ElectricityProtection")]
	public async Task ElectricityProtection([FromBody] ElectricityProtectionInput input)
	{
		long? meterId = input.MeterId;
		long tenantId = long.Parse(App.User.FindFirst("TenantId").Value);
		if (!meterId.HasValue)
		{
			await (from s in _rep.Context.Updateable<ElectricMeter>().SetColumns((ElectricMeter s) => new ElectricMeter
				{
					ElectricityProtectionBegin = input.ElectricityProtectionBegin,
					ElectricityProtectionEnd = input.ElectricityProtectionEnd,
					IsElectricityProtection = input.IsElectricityProtection
				})
				where s.TenantId == (long?)tenantId
				select s).ExecuteCommandAsync();
		}
		else
		{
			await (from s in _rep.Context.Updateable<ElectricMeter>().SetColumns((ElectricMeter s) => new ElectricMeter
				{
					ElectricityProtectionBegin = input.ElectricityProtectionBegin,
					ElectricityProtectionEnd = input.ElectricityProtectionEnd,
					IsElectricityProtection = input.IsElectricityProtection
				})
				where s.TenantId == (long?)tenantId && (long?)s.Id == meterId
				select s).ExecuteCommandAsync();
		}
	}

	/// <summary>
	/// 设置是否允许业主控制电表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/SetOwnerControl")]
	public async Task SetOwnerControl([FromBody] OwnerControlInput input)
	{
		long? meterId = input.MeterId;
		long tenantId = long.Parse(App.User.FindFirst("TenantId").Value);
		if (!meterId.HasValue)
		{
			await (from s in _rep.Context.Updateable<ElectricMeter>().SetColumns((ElectricMeter s) => new ElectricMeter
				{
					OwnerControl = input.OwnerControl
				})
				where s.TenantId == (long?)tenantId
				select s).ExecuteCommandAsync();
		}
		else
		{
			await (from s in _rep.Context.Updateable<ElectricMeter>().SetColumns((ElectricMeter s) => new ElectricMeter
				{
					OwnerControl = input.OwnerControl
				})
				where s.TenantId == (long?)tenantId && (long?)s.Id == meterId
				select s).ExecuteCommandAsync();
		}
	}

	/// <summary>
	/// 分页查询电表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/electricity/subsidypage")]
	public async Task<dynamic> SubsidyPage([FromQuery] SubsidyMeterInput input)
	{
		List<long> roomIds = new List<long>();
		if (input.BuildingId.HasValue)
		{
			List<long> list2 = roomIds;
			list2.AddRange(await (from u in _rep.Context.Queryable<Room>()
				where (long?)u.BuildingId == input.BuildingId
				select u.Id).ToListAsync());
		}
		ISugarQueryable<ElectricMeter> query = _rep.Context.Queryable<ElectricMeter>().WhereIF(!string.IsNullOrWhiteSpace(input.Imei), (ElectricMeter u) => u.Sn.Contains(input.Imei.Trim())).WhereIF(!string.IsNullOrWhiteSpace(input.Name), (ElectricMeter u) => u.Name.Contains(input.Name.Trim()))
			.WhereIF(!string.IsNullOrWhiteSpace(input.Sn), (ElectricMeter u) => u.Sn.Contains(input.Sn.Trim()))
			.WhereIF(input.IsSubsidy.HasValue, (ElectricMeter u) => (int?)u.IsSubsidy == input.IsSubsidy)
			.WhereIF(input.RoomId.HasValue, (ElectricMeter u) => u.RoomId == input.RoomId)
			.WhereIF(!input.RoomId.HasValue && roomIds.Count > 0, (ElectricMeter u) => roomIds.Contains(u.RoomId.Value));
		ISugarQueryable<SubsidyMeterOutPut> info = (from u in query
			select new SubsidyMeterOutPut
			{
				SignalStatus = u.SignalStatus,
				Sn = u.Sn,
				CombinedActiveSharpElectricEnergy = u.CombinedActiveSharpElectricEnergy,
				GateStatus = u.GateStatus,
				Addr = u.Addr,
				CollectorId = u.CollectorId,
				CombinedActiveFlatElectricEnergy = u.CombinedActiveFlatElectricEnergy,
				CombinedActivePeakElectricEnergy = u.CombinedActivePeakElectricEnergy,
				CombinedActiveTotalElectricEnergy = u.CombinedActiveTotalElectricEnergy,
				CombinedActiveValleyElectricEnergy = u.CombinedActiveValleyElectricEnergy,
				TenantId = u.TenantId,
				CreateTime = u.CreateTime,
				CreateUserId = u.CreateUserId,
				Id = u.Id,
				IsDelete = u.IsDelete,
				Multiplier = u.Multiplier,
				Name = u.Name,
				PriceRuleId = u.PriceRuleId,
				ProtocolType = u.ProtocolType,
				RoomId = u.RoomId,
				RoomName = from s3 in SqlFunc.Subqueryable<Room>()
					where (long?)s3.Id == u.RoomId
					select s3.Name,
				UpdateTime = u.UpdateTime,
				UpdateUserId = u.UpdateUserId,
				IssuedStatus = u.IssuedStatus,
				LowAddr = u.LowAddr,
				LabelId = u.LabelId,
				IsPublicMeter = u.IsPublicMeter,
				ElectricityProtectionBegin = u.ElectricityProtectionBegin,
				ElectricityProtectionEnd = u.ElectricityProtectionEnd,
				IsElectricityProtection = u.IsElectricityProtection,
				LatestMeterReadingTime = u.LatestMeterReadingTime,
				Latitude = u.Latitude,
				Longitude = u.Longitude,
				IsSubsidy = u.IsSubsidy,
				SubsidyFee = u.SubsidyFee,
				NowSubsidyFee = u.NowSubsidyFee,
				SubsidyTime = u.SubsidyTime,
				ReservationSubsidyTime = u.ReservationSubsidyTime,
				OwnerControl = u.OwnerControl,
				ReservationSubsidyFee = u.ReservationSubsidyFee
			} into u
			orderby u.SignalStatus descending
			select u).OrderBuilder(input);
		SqlSugarPagedList<SubsidyMeterOutPut> list = await info.ToPagedListAsync(input.Page, input.PageSize);
		List<long?> roomid = list.Items.Select((SubsidyMeterOutPut x) => x.RoomId).Distinct().ToList();
		if (roomid.Count > 0)
		{
			var buildingInfo = await (from a in _rep.Context.Queryable<Room>().LeftJoin((Room a, Building b) => a.BuildingId == b.Id)
				where roomid.Contains(a.Id)
				select a).Select((Room a, Building b) => new { a.Id, b.Name }).ToListAsync();
			list.Items.ToList().ForEach(delegate(SubsidyMeterOutPut x)
			{
				x.BuildingName = buildingInfo.Where(u => u.Id == x.RoomId).FirstOrDefault()?.Name;
			});
		}
		return list;
	}

	/// <summary>
	/// 电表金额补贴
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/setsubsidy")]
	[OperationLog("手续费设置", "sn,reservationSubsidyFee,reservationSubsidyTime,setIsSubsidy")]
	public async Task SetSubsidy([FromBody] SubsidyMeterEditInput input)
	{
		if (input.MeterId.HasValue)
		{
			return;
		}
		List<long> roomIds = new List<long>();
		if (input.BuildingId.HasValue)
		{
			List<long> list2 = roomIds;
			list2.AddRange(await (from u in _rep.Context.Queryable<Room>()
				where (long?)u.BuildingId == input.BuildingId
				select u.Id).ToListAsync());
		}
		List<ElectricMeter> list = await _rep.Context.Queryable<ElectricMeter>().WhereIF(!string.IsNullOrWhiteSpace(input.Name), (ElectricMeter u) => u.Name.Contains(input.Name.Trim())).WhereIF(!string.IsNullOrWhiteSpace(input.Sn), (ElectricMeter u) => u.Sn.Contains(input.Sn.Trim()))
			.WhereIF(input.IsSubsidy.HasValue, (ElectricMeter u) => (int?)u.IsSubsidy == input.IsSubsidy)
			.WhereIF(input.RoomId.HasValue, (ElectricMeter u) => u.RoomId == input.RoomId)
			.WhereIF(!input.RoomId.HasValue && roomIds.Count > 0, (ElectricMeter u) => roomIds.Contains(u.RoomId.Value))
			.WhereIF(input.MeterId.HasValue, (ElectricMeter u) => (long?)u.Id == input.MeterId)
			.ToListAsync();
		list.ForEach(delegate(ElectricMeter u)
		{
			u.ReservationSubsidyTime = input.ReservationSubsidyTime;
			u.IsSubsidy = input.SetIsSubsidy;
			u.ReservationSubsidyFee = input.ReservationSubsidyFee;
		});
		await _rep.Context.Updateable(list).UpdateColumns((ElectricMeter u) => new { u.ReservationSubsidyFee, u.ReservationSubsidyTime, u.IsSubsidy }).ExecuteCommandAsync();
	}

	/// <summary>
	/// 获取原电表的信息
	/// </summary>
	/// <param name="id"></param>
	/// <returns></returns>
	[HttpGet("/electricity/getorimeterinfo")]
	public async Task<dynamic> GetOriMeterInfo([FromQuery] long id)
	{
		ElectricMeter meter = await _rep.GetFirstAsync((ElectricMeter u) => u.Id == id);
		if (meter == null)
		{
			throw Oops.Bah("当前电表不存在或已被删除，请刷新后重试");
		}
		bool hasroom = meter.RoomId.HasValue;
		if (meter.RoomId.HasValue)
		{
			hasroom = await _rep.Context.Queryable<Room>().AnyAsync((Room u) => (long?)u.Id == meter.RoomId);
		}
		bool hasprice = meter.PriceRuleId.HasValue;
		ElectricityPriceRule priceRule = null;
		if (meter.PriceRuleId.HasValue)
		{
			priceRule = await _rep.Context.Queryable<ElectricityPriceRule>().FirstAsync((ElectricityPriceRule u) => (long?)u.Id == meter.PriceRuleId);
			if (priceRule == null)
			{
				hasprice = false;
			}
		}
		return new { meter, hasroom, hasprice, priceRule };
	}

	/// <summary>
	/// 换表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/electricity/changeelectricity")]
	public async Task ChangeElectricity([FromBody] ChangeElectricityInput input)
	{
		ElectricMeter orimeter = await (from u in _rep.AsQueryable()
			where u.Id == input.Id
			select u).FirstAsync();
		if (orimeter == null)
		{
			throw Oops.Bah("当前电表不存在或已被删除，请刷新后重试");
		}
		try
		{
			ElectricMeter entity = input.Adapt<ElectricMeter>();
			if (!entity.BaseCombinedActiveValleyDeepElectricEnergy.HasValue)
			{
				entity.BaseCombinedActiveValleyDeepElectricEnergy = default(decimal);
			}
			if (await _rep.IsAnyAsync((ElectricMeter u) => u.Sn == entity.Sn))
			{
				throw Oops.Oh(ErrorCodeEnum.R2002);
			}
			await _rep.Context.Ado.BeginTranAsync();
			await _balanceRep.Context.Ado.BeginTranAsync();
			await _rep.DeleteAsync(orimeter);
			await _rep.InsertAsync(entity);
			ChangeEMeterRecord record = input.Adapt<ChangeEMeterRecord>();
			record.Id = 0L;
			record.OriId = orimeter.Id;
			record.OriSn = orimeter.Sn;
			record.OriCombinedActiveTotalElectricEnergy = orimeter.CombinedActiveTotalElectricEnergy;
			record.OriCombinedActiveSharpElectricEnergy = orimeter.CombinedActiveSharpElectricEnergy;
			record.OriCombinedActiveFlatElectricEnergy = orimeter.CombinedActiveFlatElectricEnergy;
			record.OriCombinedActivePeakElectricEnergy = orimeter.CombinedActivePeakElectricEnergy;
			record.OriCombinedActiveValleyElectricEnergy = orimeter.CombinedActiveValleyElectricEnergy;
			if (orimeter.RoomId.HasValue && orimeter.PriceRuleId.HasValue)
			{
				Room room = await (from u in _rep.Context.Queryable<Room>()
					where (long?)u.Id == input.RoomId
					select u).FirstAsync();
				if (room != null)
				{
					ElectricityPriceRule rule = await (from u in _rep.Context.Queryable<ElectricityPriceRule>()
						where (long?)u.Id == orimeter.PriceRuleId
						select u).FirstAsync();
					if (rule != null)
					{
						decimal? amount = default(decimal);
						decimal? price;
						if (rule.Type == 0)
						{
							decimal CombinedActiveTotalElectricEnergy = input.RealCombinedActiveTotalElectricEnergy.GetValueOrDefault() - orimeter.CombinedActiveTotalElectricEnergy.GetValueOrDefault();
							decimal value = CombinedActiveTotalElectricEnergy;
							price = rule.Price;
							amount = (decimal?)value * price * (decimal?)(decimal)orimeter.Multiplier;
							decimal? num = amount;
							if ((num.GetValueOrDefault() > default(decimal)) & num.HasValue)
							{
								record.Amount = amount.GetValueOrDefault();
								await (from u in _rep.Context.Updateable<Room>()
									where u.Id == room.Id
									select u).SetColumns((Room u) => (decimal?)u.Balance == (decimal?)u.Balance - amount).ExecuteCommandAsync();
							}
						}
						else
						{
							decimal CombinedActiveSharpElectricEnergy = input.RealCombinedActiveSharpElectricEnergy.GetValueOrDefault() - orimeter.CombinedActiveSharpElectricEnergy.GetValueOrDefault();
							decimal CombinedActivePeakElectricEnergy = input.RealCombinedActivePeakElectricEnergy.GetValueOrDefault() - orimeter.CombinedActivePeakElectricEnergy.GetValueOrDefault();
							decimal CombinedActiveFlatElectricEnergy = input.RealCombinedActiveFlatElectricEnergy.GetValueOrDefault() - orimeter.CombinedActiveFlatElectricEnergy.GetValueOrDefault();
							decimal CombinedActiveValleyElectricEnergy = input.RealCombinedActiveValleyElectricEnergy.GetValueOrDefault() - orimeter.CombinedActiveValleyElectricEnergy.GetValueOrDefault();
							decimal value = CombinedActiveSharpElectricEnergy;
							price = rule.SharpPrice;
							decimal? sharpAmount = (decimal?)value * price * (decimal?)(decimal)orimeter.Multiplier;
							value = CombinedActivePeakElectricEnergy;
							price = rule.PeakPrice;
							decimal? peakAmount = (decimal?)value * price * (decimal?)(decimal)orimeter.Multiplier;
							value = CombinedActiveFlatElectricEnergy;
							price = rule.FlatPrice;
							decimal? flatAmount = (decimal?)value * price * (decimal?)(decimal)orimeter.Multiplier;
							value = CombinedActiveValleyElectricEnergy;
							price = rule.ValleyPrice;
							decimal? num2 = (decimal?)value * price * (decimal?)(decimal)orimeter.Multiplier;
							amount = sharpAmount + peakAmount + flatAmount + num2;
							record.Amount = amount.GetValueOrDefault();
							price = amount;
							if ((price.GetValueOrDefault() > default(decimal)) & price.HasValue)
							{
								await (from u in _rep.Context.Updateable<Room>()
									where u.Id == room.Id
									select u).SetColumns((Room u) => (decimal?)u.Balance == (decimal?)u.Balance - amount).ExecuteCommandAsync();
							}
						}
						price = amount;
						if ((price.GetValueOrDefault() > default(decimal)) & price.HasValue)
						{
							await _roomService.AddRoomBalanceRecord(_balanceRep.Context, room.Id, record.Id, 1, -amount.Value, room.TenantId.Value, $"换表结算({orimeter.Name}:{orimeter.Sn})");
						}
					}
				}
			}
			await _rep.Context.Insertable(record).ExecuteCommandAsync();
			await _rep.Context.Ado.CommitTranAsync();
			await _balanceRep.Context.Ado.CommitTranAsync();
		}
		catch (Exception ex)
		{
			await _rep.Context.Ado.RollbackTranAsync();
			await _balanceRep.Context.Ado.RollbackTranAsync();
			if (!(ex is Exception source))
			{
				throw ex;
			}
			ExceptionDispatchInfo.Capture(source).Throw();
		}
	}

	/// <summary>
	/// 获取换表记录
	/// </summary>
	/// <param name="id"></param>
	/// <returns></returns>
	[HttpGet("/electricity/getchangeemeterrecord")]
	public async Task<List<ChangeEMeterRecord>> GetChangeEMeterRecord([FromQuery] long id)
	{
		return await (from u in _rep.Context.Queryable<ChangeEMeterRecord>()
			where u.OriId == id
			select u).ToListAsync();
	}

	/// <summary>
	/// 获取电表详情内容
	/// </summary>
	/// <param name="id"></param>
	/// <returns></returns>
	[HttpGet("/electricity/getelectricitydetail")]
	public async Task<dynamic> GetElectricityDetail([FromQuery] long id)
	{
		ISugarQueryable<ElectricMeter> query = from u in _rep.Context.Queryable<ElectricMeter>()
			where u.Id == id
			select u;
		ISugarQueryable<SubsidyMeterOutPut> info = query.Select((ElectricMeter u) => new SubsidyMeterOutPut
		{
			SignalStatus = u.SignalStatus,
			Sn = u.Sn,
			CombinedActiveSharpElectricEnergy = u.CombinedActiveSharpElectricEnergy,
			GateStatus = u.GateStatus,
			Addr = u.Addr,
			CollectorId = u.CollectorId,
			CombinedActiveFlatElectricEnergy = u.CombinedActiveFlatElectricEnergy,
			CombinedActivePeakElectricEnergy = u.CombinedActivePeakElectricEnergy,
			CombinedActiveTotalElectricEnergy = u.CombinedActiveTotalElectricEnergy,
			CombinedActiveValleyElectricEnergy = u.CombinedActiveValleyElectricEnergy,
			TenantId = u.TenantId,
			CreateTime = u.CreateTime,
			CreateUserId = u.CreateUserId,
			Id = u.Id,
			IsDelete = u.IsDelete,
			Multiplier = u.Multiplier,
			Name = u.Name,
			PriceRuleId = u.PriceRuleId,
			PriceName = from s4 in SqlFunc.Subqueryable<ElectricityPriceRule>()
				where (long?)s4.Id == u.PriceRuleId
				select s4.Name,
			ProtocolType = u.ProtocolType,
			RoomId = u.RoomId,
			RoomName = from s3 in SqlFunc.Subqueryable<Room>()
				where (long?)s3.Id == u.RoomId
				select s3.Name,
			RoomBalance = from s3 in SqlFunc.Subqueryable<Room>()
				where (long?)s3.Id == u.RoomId
				select s3.Balance,
			BuildingId = u.BuildingId,
			BuildingName = from s6 in SqlFunc.Subqueryable<Building>()
				where (long?)s6.Id == u.BuildingId
				select s6.Name,
			UpdateTime = u.UpdateTime,
			UpdateUserId = u.UpdateUserId,
			IssuedStatus = u.IssuedStatus,
			LowAddr = u.LowAddr,
			LabelId = u.LabelId,
			IsPublicMeter = u.IsPublicMeter,
			LabelName = from s5 in SqlFunc.Subqueryable<LabelManagement>()
				where (long?)s5.Id == u.LabelId
				select s5.Name,
			ElectricityProtectionBegin = u.ElectricityProtectionBegin,
			ElectricityProtectionEnd = u.ElectricityProtectionEnd,
			IsElectricityProtection = u.IsElectricityProtection,
			LatestMeterReadingTime = u.LatestMeterReadingTime,
			Latitude = u.Latitude,
			Longitude = u.Longitude,
			OwnerControl = u.OwnerControl,
			IsSubsidy = u.IsSubsidy,
			SubsidyFee = u.SubsidyFee,
			NowSubsidyFee = u.NowSubsidyFee,
			ReservationSubsidyFee = u.ReservationSubsidyFee,
			SubsidyTime = u.SubsidyTime,
			ReservationSubsidyTime = u.ReservationSubsidyTime,
			LastOnlineTime = u.LastOnlineTime
		});
		return await info.FirstAsync();
	}

	/// <summary>
	/// 获取电表的树结构
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/electricity/getelectricitytree")]
	public async Task<List<MeterOutPut>> GetElectricityTree([FromQuery] ElectricMeteInput input)
	{
		ISugarQueryable<ElectricMeter> query = _rep.Context.Queryable<ElectricMeter>().WhereIF(!string.IsNullOrWhiteSpace(input.Name), (ElectricMeter u) => u.Name.Contains(input.Name.Trim())).WhereIF(!string.IsNullOrWhiteSpace(input.Sn), (ElectricMeter u) => u.Sn.Contains(input.Sn.Trim()))
			.WhereIF(input.SignalStatus.HasValue, (ElectricMeter u) => (int?)u.SignalStatus == input.SignalStatus)
			.WhereIF(input.GateStatus.HasValue, (ElectricMeter u) => (int?)u.GateStatus == input.GateStatus)
			.WhereIF(input.IssuedStatus.HasValue, (ElectricMeter u) => (int?)u.IssuedStatus == input.IssuedStatus)
			.WhereIF(input.BuildingId.HasValue, (ElectricMeter u) => u.BuildingId == input.BuildingId)
			.WhereIF(input.RoomId.HasValue, (ElectricMeter u) => u.RoomId == input.RoomId)
			.WhereIF(input.ProtocolType.HasValue, (ElectricMeter u) => (int?)u.ProtocolType == input.ProtocolType)
			.WhereIF(input.PriceRuleId.HasValue, (ElectricMeter u) => u.PriceRuleId == input.PriceRuleId)
			.WhereIF(input.IsPublicMeter.HasValue, (ElectricMeter u) => (bool?)u.IsPublicMeter == input.IsPublicMeter)
			.WhereIF(input.IsElectricityProtection.HasValue, (ElectricMeter u) => (bool?)u.IsElectricityProtection == input.IsElectricityProtection)
			.WhereIF(input.OwnerControl.HasValue, (ElectricMeter u) => (bool?)u.OwnerControl == input.OwnerControl)
			.WhereIF(input.IsSubsidy.HasValue, (ElectricMeter u) => (int?)u.IsSubsidy == input.IsSubsidy)
			.WhereIF(input.LabelId.HasValue, (ElectricMeter u) => u.LabelId == input.LabelId);
		ISugarQueryable<MeterOutPut> info = (from u in query
			select new MeterOutPut
			{
				Sn = u.Sn,
				TenantId = u.TenantId,
				CreateTime = u.CreateTime,
				CreateUserId = u.CreateUserId,
				Id = u.Id,
				Pid = u.Pid,
				IsDelete = u.IsDelete,
				Name = u.Name,
				ProtocolType = u.ProtocolType,
				RoomId = u.RoomId,
				BuildingId = u.BuildingId,
				UpdateTime = u.UpdateTime,
				UpdateUserId = u.UpdateUserId
			} into u
			orderby u.CreateTime descending
			select u).OrderBuilder(input);
		return await info.ToTreeAsync((MeterOutPut u) => u.Children, (MeterOutPut u) => u.Pid, 0, (MeterOutPut u) => u.Id);
	}

	/// <summary>
	/// 获取可以选择的电表
	/// </summary>
	/// <param name="ids"></param>
	/// <returns></returns>
	[HttpPost("/electricity/getcanselectelectricity")]
	public async Task<dynamic> GetCanSelectElectricity([FromBody] List<long> ids)
	{
		List<MeterOutPut> allmeters = await (from u in _rep.AsQueryable()
			select new MeterOutPut
			{
				Id = u.Id,
				Name = u.Name,
				Sn = u.Sn,
				Pid = u.Pid
			}).ToListAsync();
		List<MeterOutPut> tmpData = allmeters.Where((MeterOutPut w) => ids.Contains(w.Id)).ToList();
		List<long> newids = new List<long>();
		for (int i = 0; i < tmpData.Count; i++)
		{
			MapChild3(tmpData[i], allmeters, newids);
		}
		return allmeters.Where((MeterOutPut w) => !newids.Contains(w.Id)).ToList();
	}

	private void MapChild3(MeterOutPut item, List<MeterOutPut> list, List<long> ids)
	{
		if (ids.Contains(item.Id))
		{
			return;
		}
		ids.Add(item.Id);
		List<MeterOutPut> children = list.Where((MeterOutPut w) => w.Pid == item.Id).ToList();
		foreach (MeterOutPut child in children)
		{
			MapChild3(child, list, ids);
		}
	}

	[HttpPost("/electricity/setparentelectricity")]
	public async Task SetParentElectricity([FromQuery] long pid, [FromBody] List<long> ids)
	{
		List<MeterOutPut> allmeters = await (from u in _rep.AsQueryable()
			select new MeterOutPut
			{
				Id = u.Id,
				Name = u.Name,
				Sn = u.Sn,
				Pid = u.Pid
			}).ToListAsync();
		List<MeterOutPut> tmpData = allmeters.Where((MeterOutPut w) => ids.Contains(w.Id)).ToList();
		List<long> newids = new List<long>();
		for (int i = 0; i < tmpData.Count; i++)
		{
			MapChild3(tmpData[i], allmeters, newids);
		}
		if (newids.Contains(pid))
		{
			throw Oops.Bah("父级节点无效，请核对总分表架构");
		}
		await (from u in _rep.Context.Updateable<ElectricMeter>().SetColumns((ElectricMeter u) => u.Pid == pid)
			where ids.Contains(u.Id)
			select u).ExecuteCommandAsync();
	}
}
